home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 50
/
Aminet 50 (2002)(GTI - Schatztruhe)[!][Aug 2002].iso
/
Aminet
/
util
/
libs
/
mpega_libmad.lha
/
mpega_libmad
/
wrap_mpega.c
< prev
next >
Wrap
C/C++ Source or Header
|
2002-06-23
|
26KB
|
1,006 lines
#include "wrap_mpega.h"
#include "compiler.h"
#include <proto/dos.h>
#include <stdlib.h>
#include <string.h>
#include "audio.h"
#include "stream.h"
#include "frame.h"
#include "synth.h"
#include "resample.h"
#include "equalizer.h"
#include "timer.h"
#include "xing.h"
#ifdef BUILD_WARPUP
#include <powerpc/powerpc.h>
#include <proto/powerpc.h>
#elif defined(BUILD_POWERUP)
#include <powerup/gcclib/powerup_protos.h>
#undef Open
#define Open PPCOpen
#undef Close
#define Close PPCClose
#undef Read
#define Read PPCRead
#undef Seek
#define Seek PPCSeek
#endif
#define DEFAULT_BUFFER_SIZE 8192
typedef struct
{
BPTR fh;
UBYTE *buffer;
ULONG streamsize;
ULONG streamskip;
MPEGA_CTRL *ctrl;
MPEGA_ACCESS *access;
struct mad_stream stream;
struct mad_frame frame;
struct mad_synth synth;
struct xing xing;
mad_timer_t timer;
struct audio_dither left_dither;
struct audio_dither right_dither;
mad_fixed_t attenuate;
struct equalizer equalizer;
struct resample_state resample[2];
mad_fixed_t resampled[2][1152];
} DecHandle;
#ifdef __PPC__
#ifdef BUILD_POWERUP
#include <powerup/ppclib/interface.h>
#define CALLHOOK(hook, object, message) \
({ ULONG ret; \
struct Caos MyCaos; \
MyCaos.M68kCacheMode = IF_CACHEFLUSHALL; \
MyCaos.PPCCacheMode = IF_CACHEFLUSHALL; \
MyCaos.a0 = (ULONG) hook; \
MyCaos.a2 = (ULONG) object; \
MyCaos.a1 = (ULONG) message; \
MyCaos.caos_Un.Function = hook->h_Entry; \
ret = PPCCallM68k(&MyCaos); \
ret; \
})
#elif defined(BUILD_WARPUP)
#define CALLHOOK(hook, object, message) \
({ ULONG ret; \
struct PPCArgs args; \
args.PP_Regs[PPREG_A0] = (ULONG)hook; \
args.PP_Regs[PPREG_A2] = (ULONG)object; \
args.PP_Regs[PPREG_A1] = (ULONG)message; \
args.PP_Code = (APTR)hook->h_Entry; \
args.PP_Offset = 0; \
args.PP_Flags = 0; \
args.PP_Stack = NULL; \
args.PP_StackSize = 0; \
Run68K(&args); \
ret = args.PP_Regs[PPREG_D0]; \
ret; \
})
#else
#include <emul/emulregs.h>
#include <emul/emulinterface.h>
#define CALLHOOK(hook, object, message) \
({ ULONG ret; \
REG_A0 = (ULONG) hook; \
REG_A2 = (ULONG) object; \
REG_A1 = (ULONG) message; \
ret = (*MyEmulHandle->EmulCallDirect68k)(hook->h_Entry); \
ret; \
})
#endif
#else
#if 0
static ULONG ASM MyCallHook(REG(a0, struct Hook *hook), REG(a2, APTR object), REG(a1, APTR message))
{
return hook->h_Entry();
}
#define CALLHOOK MyCallHook
#else
#define CALLHOOK(hook, object, message) \
({ register ULONG ret __asm("d0"); \
register struct Hook *_hook __asm("a0") = hook; \
register APTR _object __asm("a2") = object; \
register APTR _message __asm("a1") = message; \
__asm volatile ("movel a0@(8:W),a3\n\t" "jsr a3@" : "=r" (ret) : "r" (_hook), "r" (_object), "r" (_message) : "d0", "a0", "a1", "a2", "a3", "cc", "memory"); \
ret; \
})
#endif
#endif
static __inline void SetStreamValues(MPEGA_STREAM *mpega_stream, struct mad_header *header)
{
switch (header->mode)
{
case MAD_MODE_SINGLE_CHANNEL:
mpega_stream->mode = MPEGA_MODE_MONO;
break;
case MAD_MODE_DUAL_CHANNEL:
mpega_stream->mode = MPEGA_MODE_DUAL;
break;
case MAD_MODE_JOINT_STEREO:
mpega_stream->mode = MPEGA_MODE_J_STEREO;
break;
case MAD_MODE_STEREO:
mpega_stream->mode = MPEGA_MODE_STEREO;
break;
default:
mpega_stream->mode = -1;
break;
}
mpega_stream->norm = ((header->flags & MAD_FLAG_LSF_EXT) ? 2 : 1);
mpega_stream->layer = header->layer;
mpega_stream->bitrate = header->bitrate / 1000;
mpega_stream->frequency = header->samplerate;
mpega_stream->channels = ((header->mode == MAD_MODE_SINGLE_CHANNEL) ? 1 : 2);
mpega_stream->private_bit = ((header->private_bits & MAD_PRIVATE_HEADER) ? 1 : 0);
mpega_stream->copyright = ((header->flags & MAD_FLAG_COPYRIGHT) ? 1 : 0);
mpega_stream->original = ((header->flags & MAD_FLAG_ORIGINAL) ? 1 : 0);
}
static __inline void ClearStreamValues(MPEGA_STREAM *mpega_stream)
{
/* Dummy values */
mpega_stream->mode = MPEGA_MODE_J_STEREO;
mpega_stream->norm = 1;
mpega_stream->layer = 3;
mpega_stream->bitrate = 128;
mpega_stream->frequency = 44100;
mpega_stream->channels = 2;
mpega_stream->private_bit = 0;
mpega_stream->copyright = 0;
mpega_stream->original = 0;
mpega_stream->ms_duration = 1000;
mpega_stream->dec_channels = 2;
mpega_stream->dec_quality = 2;
mpega_stream->dec_frequency = 44100;
}
static __inline void SetStreamOptions(MPEGA_STREAM *mpega_stream, MPEGA_CTRL *ctrl, DecHandle *dechandle)
{
MPEGA_LAYER *layer = ((mpega_stream->layer == 3) ? (&ctrl->layer_3) : (&ctrl->layer_1_2));
MPEGA_OUTPUT *output;
LONG freq;
if (layer->force_mono || mpega_stream->channels == 1)
{
output = &layer->mono;
mpega_stream->dec_channels = 1;
} else {
output = &layer->stereo;
mpega_stream->dec_channels = 2;
}
if (output->quality == 0)
{
switch (output->freq_div)
{
case 4:
if ((freq = mpega_stream->frequency / 4) > 8000)
{
mad_stream_options(&dechandle->stream, MAD_OPTION_QUARTSAMPLERATE);
mpega_stream->dec_frequency = freq;
break;
}
/* Fall through */
case 2:
if ((freq = mpega_stream->frequency / 2) > 8000)
{
mad_stream_options(&dechandle->stream, MAD_OPTION_HALFSAMPLERATE);
mpega_stream->dec_frequency = freq;
break;
}
/* Fall through */
case 0:
if ((freq = mpega_stream->frequency) > output->freq_max)
{
LONG freqdiv = freq / output->freq_max;
switch (freqdiv)
{
case 6:
case 5:
case 4:
freq /= 4;
mad_stream_options(&dechandle->stream, MAD_OPTION_QUARTSAMPLERATE);
resample_init(&dechandle->resample[0], freq, output->freq_max);
if (mpega_stream->dec_channels == 2)
resample_init(&dechandle->resample[1], freq, output->freq_max);
mpega_stream->dec_frequency = output->freq_max;
break;
case 3:
case 2:
freq /= 2;
mad_stream_options(&dechandle->stream, MAD_OPTION_HALFSAMPLERATE);
resample_init(&dechandle->resample[0], freq, output->freq_max);
if (mpega_stream->dec_channels == 2)
resample_init(&dechandle->resample[1], freq, output->freq_max);
mpega_stream->dec_frequency = output->freq_max;
break;
default:
mad_stream_options(&dechandle->stream, 0);
resample_init(&dechandle->resample[0], mpega_stream->frequency, freq);
if (mpega_stream->dec_channels == 2)
resample_init(&dechandle->resample[1], mpega_stream->frequency, freq);
mpega_stream->dec_frequency = freq;
break;
}
break;
}
/* Fall through */
default:
mad_stream_options(&dechandle->stream, 0);
mpega_stream->dec_frequency = mpega_stream->frequency;
break;
}
} else {
switch (output->freq_div)
{
case 4:
if ((freq = mpega_stream->frequency / 4) > 8000)
{
resample_init(&dechandle->resample[0], mpega_stream->frequency, freq);
if (mpega_stream->dec_channels == 2)
resample_init(&dechandle->resample[1], mpega_stream->frequency, freq);
mpega_stream->dec_frequency = freq;
break;
}
/* Fall through */
case 2:
if ((freq = mpega_stream->frequency / 2) > 8000)
{
resample_init(&dechandle->resample[0], mpega_stream->frequency, freq);
if (mpega_stream->dec_channels == 2)
resample_init(&dechandle->resample[1], mpega_stream->frequency, freq);
mpega_stream->dec_frequency = freq;
break;
}
/* Fall through */
case 0:
if ((freq = mpega_stream->frequency) > output->freq_max)
{
resample_init(&dechandle->resample[0], freq, output->freq_max);
if (mpega_stream->dec_channels == 2)
resample_init(&dechandle->resample[1], freq, output->freq_max);
mpega_stream->dec_frequency = output->freq_max;
break;
}
/* Fall through */
default:
mpega_stream->dec_frequency = mpega_stream->frequency;
break;
}
}
if ((mpega_stream->dec_quality = output->quality) < 2) dechandle->stream.options |= MAD_OPTION_IGNORECRC;
}
static __inline ULONG CheckID3(UBYTE *buffer)
{
ULONG size = 0;
if (buffer[0]=='I' && buffer[1]=='D' && buffer[2]=='3' && buffer[3]<0xFF && buffer[4]<0xFF && buffer[6]<0x80 && buffer[7]<0x80 && buffer[8]<0x80 && buffer[9]<0x80)
{
size = 10 + (((buffer[6] & 0x7F) << 21) | ((buffer[7] & 0x7F) << 14) | ((buffer[8] & 0x7F) << 7) | buffer[9] & 0x7F);
if (buffer[5] & 0x10)
size += 10;
}
return size;
}
static __inline LONG ReadFunc(DecHandle *dechandle, UBYTE *buffer, LONG len)
{
MPEGA_CTRL *ctrl = dechandle->ctrl;
LONG bytes;
if (ctrl->bs_access == NULL)
{
bytes = Read(dechandle->fh, buffer, len);
} else {
MPEGA_ACCESS *access = dechandle->access;
access->func = MPEGA_BSFUNC_READ;
access->data.read.buffer = buffer;
access->data.read.num_bytes = len;
bytes = CALLHOOK(ctrl->bs_access, (APTR)dechandle->fh, access);
}
return bytes;
}
static LONG InitDecoder(MPEGA_STREAM *mpega_stream, MPEGA_CTRL *ctrl)
{
DecHandle *dechandle = (DecHandle *) mpega_stream->handle;
LONG bytes;
mad_stream_init(&dechandle->stream);
mad_frame_init(&dechandle->frame);
mad_synth_init(&dechandle->synth);
xing_init(&dechandle->xing);
resample_init(&dechandle->resample[0], 44100, 44100);
resample_init(&dechandle->resample[1], 44100, 44100);
mad_timer_reset(&dechandle->timer);
dechandle->attenuate = MAD_F_ONE;
bytes = ReadFunc(dechandle, dechandle->buffer, ctrl->stream_buffer_size);
if (bytes > 0)
{
ULONG skip;
ClearStreamValues(mpega_stream);
dechandle->streamskip = skip = CheckID3(dechandle->buffer);
if (dechandle->streamsize == 0) dechandle->streamsize = ((bytes > skip) ? (bytes) : (skip));
/* Ensure that we have something to decode */
if (skip > (bytes - 2000))
{
LONG len = 0, size = bytes;
if (skip < size)
{
bytes = len = size - skip;
memmove(dechandle->buffer, dechandle->buffer + (size - len), len);
skip = size;
}
while (skip >= size)
{
skip -= size;
size = ReadFunc(dechandle, dechandle->buffer + len, ctrl->stream_buffer_size - len);
if (size <= 0) return 0;
}
if (skip)
{
bytes = len = size - skip;
memmove(dechandle->buffer, dechandle->buffer + (size - len), len);
size = ReadFunc(dechandle, dechandle->buffer + len, ctrl->stream_buffer_size - len);
}
if (size > 0) bytes += size;
}
bzero(dechandle->buffer + bytes, MAD_BUFFER_GUARD);
mad_stream_buffer(&dechandle->stream, dechandle->buffer, bytes);
dechandle->stream.sync = 0;
mad_stream_options(&dechandle->stream, MAD_OPTION_IGNORECRC);
if (mad_frame_decode(&dechandle->frame, &dechandle->stream) == -1)
{
while (MAD_RECOVERABLE(dechandle->stream.error))
{
dechandle->stream.error = 0;
if (mad_frame_decode(&dechandle->frame, &dechandle->stream) == 0) break;
}
if (dechandle->stream.error)
{
mad_stream_options(&dechandle->stream, 0);
if (ctrl->check_mpeg && dechandle->streamsize > bytes) return 0;
return 1;
}
}
mad_stream_options(&dechandle->stream, 0);
SetStreamValues(mpega_stream, &dechandle->frame.header);
if (xing_parse(&dechandle->xing, dechandle->stream.anc_ptr, dechandle->stream.anc_bitlen) == 0)
{
skip = dechandle->stream.next_frame - dechandle->buffer;
dechandle->streamskip += skip;
if (dechandle->xing.flags & XING_FRAMES)
{
ULONG seconds;
mad_timer_t total = dechandle->frame.header.duration;
mad_timer_multiply(&total, dechandle->xing.frames);
mpega_stream->ms_duration = mad_timer_count(total, MAD_UNITS_MILLISECONDS);
seconds = ((mpega_stream->ms_duration > 1000) ? (mpega_stream->ms_duration / 1000) : (1));
if (dechandle->xing.flags & XING_BYTES)
{
mpega_stream->bitrate = ((dechandle->xing.bytes / 125) / seconds);
} else {
mpega_stream->bitrate = (((dechandle->streamsize - dechandle->streamskip) / 125) / seconds);
}
}
} else {
skip = dechandle->stream.this_frame - dechandle->buffer;
dechandle->streamskip += skip;
if (dechandle->streamsize)
{
#if 0
mad_timer_t total = dechandle->frame.header.duration;
mad_timer_multiply(&total, ((dechandle->streamsize - dechandle->streamskip) / (dechandle->stream.next_frame - dechandle->stream.this_frame)));
mpega_stream->ms_duration = mad_timer_count(total, MAD_UNITS_MILLISECONDS);
#else
/* This will overflow on files over 500MB, but is more accurate than the above */
mpega_stream->ms_duration = ((dechandle->streamsize - dechandle->streamskip) * 8) / ((mpega_stream->bitrate) ? (mpega_stream->bitrate) : (8));
#endif
}
mad_stream_buffer(&dechandle->stream, dechandle->buffer + skip, bytes - skip);
mad_frame_mute(&dechandle->frame);
}
SetStreamOptions(mpega_stream, ctrl, dechandle);
return 1;
}
return 0;
}
static void FinishDecoder(DecHandle *dechandle)
{
resample_finish(&dechandle->resample[0]);
resample_finish(&dechandle->resample[1]);
xing_finish(&dechandle->xing);
mad_synth_finish(&dechandle->synth);
mad_frame_finish(&dechandle->frame);
mad_stream_finish(&dechandle->stream);
}
static __inline LONG ValidateFrequency(LONG freq)
{
if (freq <= 0) return 48000;
if (freq <= 8000) return 8000;
if (freq <= 11025) return 11025;
if (freq <= 12000) return 12000;
if (freq <= 16000) return 16000;
if (freq <= 22050) return 22050;
if (freq <= 24000) return 24000;
if (freq <= 32000) return 32000;
if (freq <= 44100) return 44100;
return 48000;
}
static __inline void ValidateCtrl(MPEGA_CTRL *ctrl)
{
if (ctrl->stream_buffer_size < DEFAULT_BUFFER_SIZE)
ctrl->stream_buffer_size = DEFAULT_BUFFER_SIZE;
if (ctrl->layer_1_2.mono.freq_div < 0)
ctrl->layer_1_2.mono.freq_div = 0;
if (ctrl->layer_1_2.mono.freq_div > 2)
ctrl->layer_1_2.mono.freq_div = 4;
if (ctrl->layer_1_2.mono.quality < 0)
ctrl->layer_1_2.mono.quality = 0;
if (ctrl->layer_1_2.mono.quality > 2)
ctrl->layer_1_2.mono.quality = 2;
if (ctrl->layer_1_2.stereo.freq_div < 0)
ctrl->layer_1_2.stereo.freq_div = 0;
if (ctrl->layer_1_2.stereo.freq_div > 2)
ctrl->layer_1_2.stereo.freq_div = 4;
if (ctrl->layer_1_2.stereo.quality < 0)
ctrl->layer_1_2.stereo.quality = 0;
if (ctrl->layer_1_2.stereo.quality > 2)
ctrl->layer_1_2.stereo.quality = 2;
ctrl->layer_1_2.mono.freq_max = ValidateFrequency(ctrl->layer_1_2.mono.freq_max);
ctrl->layer_1_2.stereo.freq_max = ValidateFrequency(ctrl->layer_1_2.stereo.freq_max);
if (ctrl->layer_3.mono.freq_div < 0)
ctrl->layer_3.mono.freq_div = 0;
if (ctrl->layer_3.mono.freq_div > 2)
ctrl->layer_3.mono.freq_div = 4;
if (ctrl->layer_3.mono.quality < 0)
ctrl->layer_3.mono.quality = 0;
if (ctrl->layer_3.mono.quality > 2)
ctrl->layer_3.mono.quality = 2;
if (ctrl->layer_3.stereo.freq_div < 0)
ctrl->layer_3.stereo.freq_div = 0;
if (ctrl->layer_3.stereo.freq_div > 2)
ctrl->layer_3.stereo.freq_div = 4;
if (ctrl->layer_3.stereo.quality < 0)
ctrl->layer_3.stereo.quality = 0;
if (ctrl->layer_3.stereo.quality > 2)
ctrl->layer_3.stereo.quality = 2;
ctrl->layer_3.mono.freq_max = ValidateFrequency(ctrl->layer_3.mono.freq_max);
ctrl->layer_3.stereo.freq_max = ValidateFrequency(ctrl->layer_3.stereo.freq_max);
}
static __inline LONG OutputPCM(MPEGA_STREAM *mpega_stream, DecHandle *dechandle, WORD *pcm[MPEGA_MAX_CHANNELS])
{
WORD *outleft = pcm[0];
WORD *outright = pcm[1];
mad_fixed_t const *left = dechandle->synth.pcm.samples[0];
mad_fixed_t const *right = dechandle->synth.pcm.samples[1];
ULONG len = dechandle->synth.pcm.length;
LONG nsamples, sample0, sample1;
nsamples = len;
if (mpega_stream->dec_channels == 1 || !outright)
{
if (dechandle->resample[0].ratio != MAD_F_ONE)
{
nsamples = resample_block(&dechandle->resample[0], len, left, dechandle->resampled[0]);
left = dechandle->resampled[0];
}
if (mpega_stream->dec_quality < 2)
{
while (len--)
{
sample0 = audio_linear_round(16, *left++);
*outleft++ = sample0 & 0x0000FFFF;
}
} else {
while (len--)
{
sample0 = audio_linear_dither(16, *left++, &dechandle->left_dither);
*outleft++ = sample0 & 0x0000FFFF;
}
}
} else { /* Stereo */
if (dechandle->resample[0].ratio != MAD_F_ONE)
{
nsamples = resample_block(&dechandle->resample[0], len, left, dechandle->resampled[0]);
resample_block(&dechandle->resample[1], len, right, dechandle->resampled[1]);
left = dechandle->resampled[0];
right = dechandle->resampled[1];
}
if (mpega_stream->dec_quality < 2)
{
while (len--)
{
sample0 = audio_linear_round(16, *left++);
sample1 = audio_linear_round(16, *right++);
*outleft++ = sample0 & 0x0000FFFF;
*outright++ = sample1 & 0x0000FFFF;
}
} else {
while (len--)
{
sample0 = audio_linear_dither(16, *left++, &dechandle->left_dither);
sample1 = audio_linear_dither(16, *right++, &dechandle->right_dither);
*outleft++ = sample0 & 0x0000FFFF;
*outright++ = sample1 & 0x0000FFFF;
}
}
}
return nsamples;
}
MPEGA_STREAM * LIBPPC WRAP_MPEGA_open(char *stream_name, MPEGA_CTRL *ctrl)
{
if (ctrl)
{
MPEGA_STREAM *mpega_stream;
if ((mpega_stream = malloc(sizeof(MPEGA_STREAM))))
{
DecHandle *dechandle;
if ((dechandle = calloc(1, sizeof(DecHandle))))
{
mpega_stream->handle = dechandle;
dechandle->fh = NULL;
dechandle->access = NULL;
ValidateCtrl(ctrl);
if ((dechandle->ctrl = malloc(sizeof(MPEGA_CTRL))))
{
bcopy(ctrl, dechandle->ctrl, sizeof(MPEGA_CTRL));
if ((dechandle->buffer = malloc(ctrl->stream_buffer_size + MAD_BUFFER_GUARD)))
{
if (ctrl->bs_access == NULL)
{
if (stream_name)
{
if ((dechandle->fh = Open(stream_name, MODE_OLDFILE)))
{
struct FileInfoBlock *fib;
dechandle->streamsize = 0;
if ((fib = malloc(sizeof(struct FileInfoBlock))))
{
if (ExamineFH(dechandle->fh, fib))
{
dechandle->streamsize = fib->fib_Size;
}
free(fib);
}
if (InitDecoder(mpega_stream, ctrl) != 0)
{
return mpega_stream;
}
Close(dechandle->fh);
}
}
} else {
MPEGA_ACCESS *access;
if ((access = malloc(sizeof(MPEGA_ACCESS))))
{
dechandle->access = access;
access->func = MPEGA_BSFUNC_OPEN;
access->data.open.stream_name = stream_name;
access->data.open.buffer_size = ctrl->stream_buffer_size;
access->data.open.stream_size = 0;
if ((dechandle->fh = CALLHOOK(ctrl->bs_access, NULL, access)))
{
dechandle->streamsize = access->data.open.stream_size;
if (InitDecoder(mpega_stream, ctrl) != 0)
{
return mpega_stream;
}
access->func = MPEGA_BSFUNC_CLOSE;
CALLHOOK(ctrl->bs_access, (APTR)dechandle->fh, access);
}
free(access);
}
}
free(dechandle->buffer);
}
free(dechandle->ctrl);
}
free(dechandle);
}
free(mpega_stream);
}
}
return NULL;
}
void LIBPPC WRAP_MPEGA_close(MPEGA_STREAM *mpega_stream)
{
if (mpega_stream)
{
DecHandle *dechandle = (DecHandle *) mpega_stream->handle;
if (dechandle)
{
MPEGA_CTRL *ctrl = dechandle->ctrl;
FinishDecoder(dechandle);
if (ctrl->bs_access == NULL)
{
if (dechandle->fh) Close(dechandle->fh);
} else {
MPEGA_ACCESS *access = dechandle->access;
access->func = MPEGA_BSFUNC_CLOSE;
CALLHOOK(ctrl->bs_access, (APTR)dechandle->fh, access);
}
if (dechandle->ctrl) free(dechandle->ctrl);
if (dechandle->buffer) free(dechandle->buffer);
if (dechandle->access) free(dechandle->access);
free(dechandle);
}
free(mpega_stream);
}
}
LONG LIBPPC WRAP_MPEGA_decode_frame(MPEGA_STREAM *mpega_stream, WORD *pcm[MPEGA_MAX_CHANNELS])
{
if (mpega_stream && pcm && pcm[0])
{
DecHandle *dechandle = (DecHandle *) mpega_stream->handle;
MPEGA_CTRL *ctrl = dechandle->ctrl;
if (mad_frame_decode(&dechandle->frame, &dechandle->stream) == -1)
{
LONG error = dechandle->stream.error;
if (error == MAD_ERROR_BUFLEN)
{
LONG bytes = ctrl->stream_buffer_size, len = 0;
if (dechandle->stream.next_frame)
{
memmove(dechandle->buffer, dechandle->stream.next_frame, len = &dechandle->buffer[bytes] - dechandle->stream.next_frame);
}
bytes = ReadFunc(dechandle, dechandle->buffer + len, bytes - len);
if (bytes == 0) return MPEGA_ERR_EOF;
if (bytes < 0) return MPEGA_ERR_BADVALUE;
bzero(dechandle->buffer + bytes + len, MAD_BUFFER_GUARD);
mad_stream_buffer(&dechandle->stream, dechandle->buffer, bytes + len);
if (mad_frame_decode(&dechandle->frame, &dechandle->stream) == -1) error = dechandle->stream.error;
else error = 0;
}
if (error)
{
switch (error)
{
case MAD_ERROR_BUFPTR:
return MPEGA_ERR_BADVALUE;
break;
case MAD_ERROR_NOMEM:
return MPEGA_ERR_MEM;
break;
case MAD_ERROR_LOSTSYNC:
return MPEGA_ERR_NO_SYNC;
break;
case MAD_ERROR_BADLAYER:
case MAD_ERROR_BADBITRATE:
case MAD_ERROR_BADSAMPLERATE:
case MAD_ERROR_BADEMPHASIS:
case MAD_ERROR_BADCRC:
case MAD_ERROR_BADBITALLOC:
case MAD_ERROR_BADSCALEFACTOR:
case MAD_ERROR_BADFRAMELEN:
case MAD_ERROR_BADBIGVALUES:
case MAD_ERROR_BADBLOCKTYPE:
case MAD_ERROR_BADSCFSI:
case MAD_ERROR_BADDATAPTR:
case MAD_ERROR_BADPART3LEN:
case MAD_ERROR_BADHUFFTABLE:
case MAD_ERROR_BADHUFFDATA:
case MAD_ERROR_BADSTEREO:
return MPEGA_ERR_BADFRAME;
break;
default:
return -error;
break;
}
}
}
mad_timer_add(&dechandle->timer, dechandle->frame.header.duration);
SetStreamValues(mpega_stream, &dechandle->frame.header);
SetStreamOptions(mpega_stream, ctrl, dechandle);
if (dechandle->attenuate != MAD_F_ONE)
equalizer_filter(&dechandle->equalizer, &dechandle->frame);
mad_synth_frame(&dechandle->synth, &dechandle->frame);
return OutputPCM(mpega_stream, dechandle, pcm);
}
return MPEGA_ERR_BADVALUE;
}
LONG LIBPPC WRAP_MPEGA_seek(MPEGA_STREAM *mpega_stream, ULONG ms_time_position)
{
if (mpega_stream)
{
DecHandle *dechandle = (DecHandle *) mpega_stream->handle;
MPEGA_CTRL *ctrl = dechandle->ctrl;
LONG pos, error;
if (dechandle->xing.flags & XING_TOC)
{
int step, i = 99;
if (dechandle->xing.flags & XING_BYTES)
{
step = dechandle->xing.bytes / 256;
} else {
step = (dechandle->streamsize - dechandle->streamskip) / 256;
}
if (ms_time_position < mpega_stream->ms_duration)
{
i = ((mpega_stream->ms_duration > 100) ? (ms_time_position / (mpega_stream->ms_duration / 100)) : (0));
if (i > 99) i = 99;
}
pos = (step * dechandle->xing.toc[i]) + dechandle->streamskip;
} else {
pos = ((((ULONG)mpega_stream->bitrate * 125UL) * (ms_time_position / 1000)) + dechandle->streamskip);
}
if (ctrl->bs_access == NULL)
{
error = Seek(dechandle->fh, pos, OFFSET_BEGINNING);
if (error > 0) error = 0;
} else {
MPEGA_ACCESS *access = dechandle->access;
access->func = MPEGA_BSFUNC_SEEK;
access->data.seek.abs_byte_seek_pos = pos;
error = CALLHOOK(ctrl->bs_access, (APTR)dechandle->fh, access);
}
if (error == 0)
{
LONG bytes;
bytes = ReadFunc(dechandle, dechandle->buffer, ctrl->stream_buffer_size);
if (bytes == 0) return MPEGA_ERR_EOF;
if (bytes < 0) return MPEGA_ERR_BADVALUE;
bzero(dechandle->buffer + bytes, MAD_BUFFER_GUARD);
mad_stream_buffer(&dechandle->stream, dechandle->buffer, bytes);
mad_frame_mute(&dechandle->frame);
mad_synth_mute(&dechandle->synth);
dechandle->stream.sync = 0;
/* If we seek somewhere other than the beginning we need to flush out junk audio */
if (pos > dechandle->streamskip)
{
mad_frame_decode(&dechandle->frame, &dechandle->stream);
mad_frame_decode(&dechandle->frame, &dechandle->stream);
mad_synth_frame(&dechandle->synth, &dechandle->frame);
}
// mad_timer_set(&dechandle->timer, 0, pos - dechandle->streamskip, (ULONG)mpega_stream->bitrate * 125);
mad_timer_set(&dechandle->timer, 0, ms_time_position, 1000);
return 0;
}
}
return MPEGA_ERR_BADVALUE;
}
LONG LIBPPC WRAP_MPEGA_time(MPEGA_STREAM *mpega_stream, ULONG *ms_time_position)
{
if (mpega_stream && ms_time_position)
{
DecHandle *dechandle = (DecHandle *) mpega_stream->handle;
*ms_time_position = mad_timer_count(dechandle->timer, MAD_UNITS_MILLISECONDS);
return 0;
}
return MPEGA_ERR_BADVALUE;
}
LONG LIBPPC WRAP_MPEGA_find_sync(UBYTE *buffer, LONG buffer_size)
{
if (buffer && buffer_size > 75)
{
LONG i = 0;
while (i < buffer_size - 1)
{
if ((buffer[i] == 0xFF) && ((buffer[i+1] & 0xE0) == 0xE0)) return i;
++i;
}
return MPEGA_ERR_NO_SYNC;
}
return MPEGA_ERR_BADVALUE;
}
LONG LIBPPC WRAP_MPEGA_scale(MPEGA_STREAM *mpega_stream, LONG scale_percent)
{
if (mpega_stream)
{
DecHandle *dechandle = (DecHandle *) mpega_stream->handle;
mad_fixed_t attenuate;
if (scale_percent >= 800) attenuate = MAD_F_MAX;
else if (scale_percent <= 0) attenuate = ((mad_fixed_t)0x00000001L);
else attenuate = (MAD_F_ONE / 100) * scale_percent;
equalizer_init(&dechandle->equalizer, attenuate);
dechandle->attenuate = attenuate;
return 0;
}
return MPEGA_ERR_BADVALUE;
}
#ifdef BUILD_POWERUP
APTR __LibFuncTable[] =
{
WRAP_MPEGA_open,
WRAP_MPEGA_close,
WRAP_MPEGA_decode_frame,
WRAP_MPEGA_seek,
WRAP_MPEGA_time,
WRAP_MPEGA_find_sync,
WRAP_MPEGA_scale,
NULL
};
#endif